Skip to content

feat: add tag filter to coding agent slack tags endpoint#338

Open
sweetmantech wants to merge 1 commit intotestfrom
feature/coding-agent-tag-filter
Open

feat: add tag filter to coding agent slack tags endpoint#338
sweetmantech wants to merge 1 commit intotestfrom
feature/coding-agent-tag-filter

Conversation

@sweetmantech
Copy link
Copy Markdown
Contributor

@sweetmantech sweetmantech commented Mar 24, 2026

Summary

  • Adds optional tag query param to GET /api/admins/coding/slack to filter mentions by Slack user_id
  • Creates new GET /api/admins/coding-agent/slack-tags endpoint returning distinct Slack users as filter options
  • Adds tests for the new getSlackTagOptionsHandler

Test plan

  • Run pnpm test lib/admins/coding-agent — all 5 tests pass
  • Verify GET /api/admins/coding/slack?tag=U123 returns only mentions from that user
  • Verify GET /api/admins/coding-agent/slack-tags returns deduplicated, alphabetically sorted users

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added API endpoint to retrieve distinct Slack users who have tagged the Coding Agent bot, with automatic deduplication and alphabetical sorting.
    • Added filtering capability to view Slack tags for a specific user.

Adds optional `tag` query param to GET /api/admins/coding/slack to filter
mentions by user_id, and creates new GET /api/admins/coding-agent/slack-tags
endpoint returning distinct Slack users for filter chip population.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Mar 24, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
recoup-api Ready Ready Preview Mar 24, 2026 2:52pm

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 24, 2026

📝 Walkthrough

Walkthrough

Added a new endpoint for retrieving distinct Slack users who tagged the Coding Agent bot, including request validation and CORS support. Enhanced the existing Slack tags handler to support filtering by a specific tag via an optional query parameter. Updated corresponding validation schemas.

Changes

Cohort / File(s) Summary
New Coding Agent Slack Tags Endpoint
app/api/admins/coding-agent/slack-tags/route.ts, lib/admins/coding-agent/getSlackTagOptionsHandler.ts, lib/admins/coding-agent/validateGetSlackTagOptionsQuery.ts
New GET endpoint that retrieves and deduplicates Slack mentions into tag options (id, name, avatar), sorted alphabetically. Includes admin auth validation and CORS preflight support.
Slack Tags Query Enhancement
lib/admins/slack/getSlackTagsHandler.ts, lib/admins/slack/validateGetSlackTagsQuery.ts
Modified handler to conditionally filter tags by a specific user_id when optional tag query parameter is provided. Updated validation schema to accept the new optional parameter.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Route as API Route<br/>(GET Handler)
    participant Validator as validateGetSlackTagOptionsQuery
    participant Handler as getSlackTagOptionsHandler
    participant DB as fetchSlackMentions

    Client->>Route: GET /api/admins/coding-agent/slack-tags
    Route->>Handler: Delegate request processing
    Handler->>Validator: Validate request & auth
    Validator->>Validator: Check admin credentials
    alt Validation fails
        Validator-->>Handler: NextResponse (error)
        Handler-->>Route: Return error response
        Route-->>Client: 401/403 response
    else Validation succeeds
        Validator-->>Handler: true
        Handler->>DB: fetchSlackMentions("all")
        DB-->>Handler: List of mentions
        Handler->>Handler: Deduplicate by user_id<br/>& sort by name
        Handler-->>Route: JSON response<br/>(status, total, tags)
        Route-->>Client: 200 with tag options
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🤖✨ A Slack tag oracle is born,
Deduped mentions, alphabetically worn,
Admins now filter with precision keen,
Where tags and periods convene,
Clean SOLID flows keep responses serene! 🎯

🚥 Pre-merge checks | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Solid & Clean Code ⚠️ Warning The pull request contains a critical validation defect where empty tag parameters bypass validation, and violates DRY/SRP principles with repeated error handling patterns across 7+ handlers. Explicitly validate and reject blank tag values before Zod parsing. Extract repeated error responses and CORS patterns into reusable utility functions and consolidate try-catch logic into middleware.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/coding-agent-tag-filter

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/admins/slack/validateGetSlackTagsQuery.ts`:
- Line 10: The query schema currently allows an empty tag string (tag:
z.string().optional()), which lets "?tag=" pass validation and later be treated
as falsy, causing unintended unfiltered results; in validateGetSlackTagsQuery
change the tag schema to reject empty strings (e.g., use
z.string().min(1).optional() or z.string().refine(s => s.trim().length >
0).optional()) so blank values are invalid (apply same change to the other
occurrences referenced around lines 30-33).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c346b622-7067-4771-a60b-6cb1450edd60

📥 Commits

Reviewing files that changed from the base of the PR and between 8306a67 and a78de15.

⛔ Files ignored due to path filters (1)
  • lib/admins/coding-agent/__tests__/getSlackTagOptionsHandler.test.ts is excluded by !**/*.test.*, !**/__tests__/** and included by lib/**
📒 Files selected for processing (5)
  • app/api/admins/coding-agent/slack-tags/route.ts
  • lib/admins/coding-agent/getSlackTagOptionsHandler.ts
  • lib/admins/coding-agent/validateGetSlackTagOptionsQuery.ts
  • lib/admins/slack/getSlackTagsHandler.ts
  • lib/admins/slack/validateGetSlackTagsQuery.ts


export const getSlackTagsQuerySchema = z.object({
period: adminPeriodSchema.default("all"),
tag: z.string().optional(),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Reject blank tag values to avoid accidental unfiltered responses

If a client sends ?tag=, Line 32 captures "", it passes validation, and filtering is skipped later because the value is falsy. That returns full results instead of signaling invalid filter input.

💡 Proposed fix
   const { searchParams } = new URL(request.url);
+  const rawTag = searchParams.get("tag");
+  if (rawTag !== null && rawTag.trim() === "") {
+    return NextResponse.json(
+      { status: "error", error: "tag must be a non-empty string" },
+      { status: 400, headers: getCorsHeaders() },
+    );
+  }
   const raw = {
     period: searchParams.get("period") ?? "all",
-    tag: searchParams.get("tag") ?? undefined,
+    tag: rawTag ?? undefined,
   };

Also applies to: 30-33

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/admins/slack/validateGetSlackTagsQuery.ts` at line 10, The query schema
currently allows an empty tag string (tag: z.string().optional()), which lets
"?tag=" pass validation and later be treated as falsy, causing unintended
unfiltered results; in validateGetSlackTagsQuery change the tag schema to reject
empty strings (e.g., use z.string().min(1).optional() or z.string().refine(s =>
s.trim().length > 0).optional()) so blank values are invalid (apply same change
to the other occurrences referenced around lines 30-33).

Copy link
Copy Markdown
Collaborator

@recoup-coding-agent recoup-coding-agent left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review: Tag filter for coding agent Slack endpoint

Summary

Clean, focused PR. Adds optional tag query param to filter GET /api/admins/coding/slack by Slack user ID, and adds a new GET /api/admins/coding-agent/slack-tags endpoint to return the distinct list of users for populating filter chips in the admin UI.

CLEAN Code Assessment

SRP ✅ Each new file has one clear responsibility.

OCP ✅ Filter logic is additive — existing behavior unchanged when tag is omitted.

DRY ✅ Reuses fetchSlackMentions, validateAdminAuth, and existing patterns.

YAGNI ✅ No over-engineering. Simple filter added exactly where needed.

Issues Found

🟡 Suggestion

Performance consideration for getSlackTagOptionsHandler: The handler calls fetchSlackMentions("all") and does client-side dedup. This works fine today, but as mention volume grows, fetching every mention just to extract unique user metadata will be slow. Consider a dedicated Supabase query for distinct users when volume warrants it.

🔵 Nit

Empty JSDoc block on makeRequest() in the test file — just remove it.

Security ✅

Admin auth enforced via validateAdminAuth on both the existing and new endpoint. No concerns.

Verdict: approve

Well-tested, follows conventions, clean implementation.

Copy link
Copy Markdown
Collaborator

@recoup-coding-agent recoup-coding-agent left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Adds a tag filter to the existing GET /api/admins/coding/slack endpoint and a new GET /api/admins/coding-agent/slack-tags endpoint returning distinct Slack users as filter-chip options. Clean, focused PR with good test coverage.

CLEAN Code Assessment

  • SRP: Each new handler/validator has exactly one responsibility.
  • DRY: Reuses existing validateAdminAuth, fetchSlackMentions, getCorsHeaders — no duplication.
  • YAGNI: No over-engineering — minimal change to add the filter.
  • Tests: Good coverage including dedup, alphabetical sort, auth failure, and upstream error cases.

Issues Found

suggestion

URL inconsistency: New endpoint is at /api/admins/coding-agent/slack-tags while the existing one is at /api/admins/coding/slack. The path diverges from the existing coding/ prefix to coding-agent/. Not a blocker, but worth aligning if the admin routes ever get reorganized.

fetchSlackMentions("all") hardcoded in getSlackTagOptionsHandler: This always fetches all-time mentions regardless of any request context. The comment says "always returns all-time unique tags" — that makes sense for a filter-options endpoint, but if the volume of mentions grows large this could become expensive. Acceptable for now.

nit

  • searchParams.get("tag") ?? undefinednull ?? undefined evaluates to undefined, which is correct, but using || undefined or searchParams.get("tag") ?? undefined are both fine. Just noting it reads slightly awkward.
  • makeRequest() in the test file has an empty JSDoc /** */ block — no description needed, but the empty block adds noise.

Security

Admin auth required on both endpoints — correct. No injection risks.

Verdict

approve — clean, well-tested, ready to merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants